package com.activiti.z_six.service.impl;

import com.activiti.z_six.entity.process.FlowEntity;
import com.activiti.z_six.entity.process.FlowSort;

import com.activiti.z_six.entity.taskAssignee.FlowElementAttrs;
import com.activiti.z_six.entity.process.FlowEnum;
import com.activiti.z_six.entity.taskAssignee.OvProcessInstance;
import com.activiti.z_six.mapper.processMapper.FlowEntityMapper;
import com.activiti.z_six.mapper.processMapper.FlowSortMapper;
import com.activiti.z_six.mapper.taskAssigneeMapper.FlowElementAttrsMapper;
import com.activiti.z_six.mapper.taskAssigneeMapper.OvProcessInstanceMapper;
import com.activiti.z_six.security.RedisUtils;
import com.activiti.z_six.service.IProcessDefinitionService;
import com.activiti.z_six.service.manager.ProcessDefManager;
import com.activiti.z_six.util.SystemConfig;

import org.activiti.bpmn.model.*;
import org.activiti.bpmn.model.Process;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class IProcessDefinitionServiceImpl implements IProcessDefinitionService {
    @Autowired //流程部署服务
    private RepositoryService repositoryService;
    @Autowired
    private OvProcessInstanceMapper ovProcessInstanceMapper;
    @Autowired //流程分类服务
    private FlowSortMapper flowSortMapper;
    @Autowired //流程定义自定义服务
    private FlowEntityMapper flowEntityMapper;
    @Autowired //redis服务
    private RedisUtils redisUtils;
    @Autowired
    private FlowElementAttrsMapper flowElementAttrsMapper;
    @Autowired
    private ProcessDefManager processDefManager;

    /**
     * 获取流程部署列表
     * @param page
     * @param pagesize
     * @param sortid
     * @param name
     * @return
     */
    @Override
    public HashMap<String ,Object> getDeployment(Integer page, Integer pagesize, String sortid, String name){
        int startIndex=(page-1)*pagesize;
        int maxIndex=startIndex+pagesize;

        //流程定义总数量
        List<ProcessDefinition> processDefinitionlist = repositoryService.createProcessDefinitionQuery()
                .latestVersion()
                .list();

        List<HashMap<String, Object>> listMap= new ArrayList<HashMap<String, Object>>();
        List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery()
                .latestVersion()
                .listPage(startIndex,maxIndex);

        list.sort((y,x)->x.getVersion()-y.getVersion());

        for (ProcessDefinition pd : list) {
            if(!SystemConfig.IsNullOrEmpty(sortid))
            {
                if(!sortid.equals(pd.getEngineVersion()))
                    continue;
            }
            if(!SystemConfig.IsNullOrEmpty(name))
            {
                if(!pd.getName().contains(name))
                    continue;
            }
            HashMap<String, Object> hashMap = new HashMap<>();
            //流程定义id
            hashMap.put("procId", pd.getId());
            //流程定义名称
            hashMap.put("name", pd.getName());
            //流程key
            hashMap.put("procKey", pd.getKey());
            //resourceName
            hashMap.put("resourceName", pd.getResourceName());
            //流程部署ID
            hashMap.put("deploymentID", pd.getDeploymentId());
            hashMap.put("flowSort",pd.getEngineVersion());
            //版本
            hashMap.put("version", pd.getVersion());
            listMap.add(hashMap);
        }
        HashMap<String ,Object> hashMap=new HashMap<>();
        hashMap.put("list",listMap);
        hashMap.put("total",processDefinitionlist.size());
        return hashMap;
    }

    /**
     * 发布流程
     * @param BPMNXml
     * @return
     */
    @Override
    public String deployWithBPMNJS(String BPMNXml){
        Deployment deployment = repositoryService.createDeployment()
                .addString("createWithBPMNJS.bpmn",BPMNXml)
                .deploy();

        OvProcessInstance ovProcessInstance=ovProcessInstanceMapper.getProcessInsByDeployId(deployment.getId());
        BpmnModel bpmnModel = repositoryService.getBpmnModel(ovProcessInstance.getId_());
        //获取流程信息
        Process process=bpmnModel.getProcesses().get(0);
        Collection<FlowElement> flowElements=process.getFlowElements();
        for(FlowElement flowElement : flowElements){
            if (flowElement instanceof UserTask){
                UserTask userTask=(UserTask) flowElement;
                String usertaskId=userTask.getId();
                String assigneeString ="";

                //获取处理人规则
                String candidateUsers=userTask.getCandidateUsers().get(0);
                String ruleName=candidateUsers.replace("$","");
                ruleName=ruleName.replace("{","");
                ruleName=ruleName.replace("}","");
                ruleName=ruleName.replace(userTask.getId()+"_","");
                //读取缓存中设置的处理人数据
                if(redisUtils.exists(usertaskId+"_"+ruleName)){
                    assigneeString=redisUtils.get(usertaskId+"_"+ruleName).toString();
                    processDefManager.deleteAssigneeUserByTaskid(usertaskId);
                    processDefManager.setAssigneeUser(assigneeString,usertaskId,ruleName);
                }
                Boolean isExists=true;
                FlowElementAttrs flowElementAttrs=flowElementAttrsMapper.getFlowElementAttrs(usertaskId);
                if(flowElementAttrs==null){
                    flowElementAttrs=new FlowElementAttrs();
                    flowElementAttrs.setId(UUID.randomUUID().toString());
                    flowElementAttrs.setTask_def_key(usertaskId);
                    isExists=false;
                }
                if(redisUtils.exists(usertaskId+"_returnWay")){
                    flowElementAttrs.setReturnWay(redisUtils.get(usertaskId+"_returnWay").toString());
                }
                else{
                    flowElementAttrs.setReturnWay("none");
                }
                if(redisUtils.exists(usertaskId+"_jumpWay")){
                    flowElementAttrs.setJumpWay(redisUtils.get(usertaskId+"_jumpWay").toString());
                }
                else{
                    flowElementAttrs.setJumpWay("none");
                }
                if(redisUtils.exists(usertaskId+"_runWay")){
                    flowElementAttrs.setRunWay(redisUtils.get(usertaskId+"_runWay").toString());
                }
                else{
                    flowElementAttrs.setRunWay("none");
                }
                if(redisUtils.exists(usertaskId+"_ccWay")){
                    flowElementAttrs.setCcWay(redisUtils.get(usertaskId+"_ccWay").toString());
                }
                else{
                    flowElementAttrs.setCcWay("none");
                }
                if(redisUtils.exists(usertaskId+"_autoCCWay")){
                    flowElementAttrs.setAutoCCWay(redisUtils.get(usertaskId+"_autoCCWay").toString());
                }
                else{
                    flowElementAttrs.setAutoCCWay("none");
                }
                if(redisUtils.exists(usertaskId+"_transfer")){
                    flowElementAttrs.setTransfer(Integer.parseInt(redisUtils.get(usertaskId+"_transfer").toString()));
                }
                else{
                    flowElementAttrs.setTransfer(0);
                }
                if(redisUtils.exists(usertaskId+"_countersign")){
                    flowElementAttrs.setCountersign(Integer.parseInt(redisUtils.get(usertaskId+"_countersign").toString()));
                }
                else{
                    flowElementAttrs.setCountersign(0);
                }
                if(redisUtils.exists(usertaskId+"_endTask")){
                    flowElementAttrs.setEndTask(Integer.parseInt(redisUtils.get(usertaskId+"_endTask").toString()));
                }
                else{
                    flowElementAttrs.setEndTask(0);
                }
                if(redisUtils.exists(usertaskId+"_refuse")){
                    flowElementAttrs.setRefuse(Integer.parseInt(redisUtils.get(usertaskId+"_refuse").toString()));
                }
                else{
                    flowElementAttrs.setRefuse(0);
                }

                flowElementAttrs.setProcess_key(ovProcessInstance.getKey_());

                if(isExists){
                    flowElementAttrsMapper.updateFlowElementAttrs(flowElementAttrs);
                }else {
                    flowElementAttrsMapper.setFlowElementAttrs(flowElementAttrs);
                }
            }
        }

        return deployment.getId();
    }

    /**
     * 更新业务配置
     * @param process_key
     * @param deploymentId
     * @param flowSort
     * @param name
     * @param form_type
     * @param formMap
     * @param form_url
     * @param mapJson
     * @return
     */
    @Override
    public String updateDeployment(String process_key, String deploymentId, String flowSort, String name,
                                      String form_type, String formMap, String form_url, String mapJson){
        //更新流程部署信息，将引擎版本号作为流程类别
        FlowEntity flowEntity=new FlowEntity();
        flowEntity.setId_(deploymentId);
        flowEntity.setProcessKey(process_key);
        flowEntity.setEngine_version_(flowSort);
        flowEntity.setName_(name);
        flowEntityMapper.updateFlowEntity(flowEntity);

        OvProcessInstance ovProcessInstance=ovProcessInstanceMapper.getProcessInsByDeployId(deploymentId);
        FlowElementAttrs flowElementAttrs=new FlowElementAttrs();
        flowElementAttrs.setProcess_key(ovProcessInstance.getKey_());
        flowElementAttrs.setForm_type(form_type);
        flowElementAttrs.setFormMap(formMap);
        flowElementAttrs.setForm_url(form_url);
        flowElementAttrsMapper.updateFlowMap(flowElementAttrs);

        return "执行成功";
    }
    @Override
    public FlowElementAttrs getFlowElementAttrs(String task_def_id){
        FlowElementAttrs flowElementAttrs=flowElementAttrsMapper.getFlowElementAttrs(task_def_id);
        return flowElementAttrs;
    }
    @Override
    public FlowElementAttrs getFlowElementFormAttrs(String process_key){
        FlowElementAttrs flowElementAttrs=flowElementAttrsMapper.getFlowElementFormAttrs(process_key);
        return flowElementAttrs;
    }
    @Override
    public HashMap<String,Object> getFlowEnum(){
        List<FlowEnum> flowEnums=flowElementAttrsMapper.enumList();
        HashMap<String,Object> hashMap=new HashMap<>();

        List<HashMap<String,Object>> taskRuleList=new ArrayList<>();

        List<HashMap<String,Object>> returnWayList=new ArrayList<>();

        List<HashMap<String,Object>> jumpWayList=new ArrayList<>();

        List<HashMap<String,Object>> ccWayList=new ArrayList<>();

        List<HashMap<String,Object>> autoCCWayList=new ArrayList<>();

        List<HashMap<String,Object>> sexSelectList=new ArrayList<>();

        List<HashMap<String,Object>> userSatetList=new ArrayList<>();

        List<HashMap<String,Object>> startRulesList=new ArrayList<>();


        for(FlowEnum fe:flowEnums){
            if(fe.getRules().equals("taskRules")){
                HashMap<String,Object> taskRules=new HashMap<>();
                taskRules.put("ruleKey",fe.getKey());
                taskRules.put("taskRuleName",fe.getName());
                taskRuleList.add(taskRules);
            }
            else if(fe.getRules().equals("returnWay")){
                HashMap<String,Object> returnWay=new HashMap<>();
                returnWay.put("returnWayKey",fe.getKey());
                returnWay.put("returnWayName",fe.getName());
                returnWayList.add(returnWay);
            }
            else if(fe.getRules().equals("jumpWay")){
                HashMap<String,Object> jumpWay=new HashMap<>();
                jumpWay.put("jumpWayKey",fe.getKey());
                jumpWay.put("jumpWayName",fe.getName());
                jumpWayList.add(jumpWay);
            }
            else if(fe.getRules().equals("ccWay")){
                HashMap<String,Object> ccWay=new HashMap<>();
                ccWay.put("ccKey",fe.getKey());
                ccWay.put("ccName",fe.getName());
                ccWayList.add(ccWay);
            }
            else if(fe.getRules().equals("autoCCWay")){
                HashMap<String,Object> autoCCWay=new HashMap<>();
                autoCCWay.put("autoCCKey",fe.getKey());
                autoCCWay.put("autoCCName",fe.getName());
                autoCCWayList.add(autoCCWay);
            }
            else if(fe.getRules().equals("sexSelect")){
                HashMap<String,Object> sexSelect=new HashMap<>();
                sexSelect.put("value",fe.getKey());
                sexSelect.put("label",fe.getName());
                sexSelectList.add(sexSelect);
            }
            else if(fe.getRules().equals("userSatet")){
                HashMap<String,Object> userSatet=new HashMap<>();
                userSatet.put("value",fe.getKey());
                userSatet.put("label",fe.getName());
                userSatetList.add(userSatet);
            }
            else if(fe.getRules().equals("startRules")){
                HashMap<String,Object> startRules=new HashMap<>();
                startRules.put("ruleKey",fe.getKey());
                startRules.put("taskRuleName",fe.getName());
                startRulesList.add(startRules);
            }
        }
        hashMap.put("taskRules",taskRuleList);
        hashMap.put("returnWay",returnWayList);
        hashMap.put("jumpWay",jumpWayList);
        hashMap.put("ccWay",ccWayList);
        hashMap.put("autoCCWay",autoCCWayList);
        hashMap.put("sexSelect",sexSelectList);
        hashMap.put("userSatet",userSatetList);
        hashMap.put("startRules",startRulesList);
        return hashMap;
    }

    /**
     * 获取流程分类分页
     * @param page
     * @param pagesize
     * @return
     */
    @Override
    public HashMap<String ,Object> getFlowSort(Integer page, Integer pagesize){
        List<FlowSort> flowSortList= flowSortMapper.getFlowSort(page,pagesize);
        List<HashMap<String, Object>> listMap= new ArrayList<HashMap<String, Object>>();
        for (FlowSort fs : flowSortList) {
            HashMap<String, Object> hashMap = new HashMap<>();
            //流程定义id
            hashMap.put("Id", fs.getId());
            //流程定义名称
            hashMap.put("name", fs.getName());
            hashMap.put("parentid", fs.getParentId());
            listMap.add(hashMap);
        }

        HashMap<String ,Object> hashMap=new HashMap<>();
        hashMap.put("list",listMap);
        hashMap.put("total",flowSortMapper.getFlowSortTotal());

        return hashMap;
    }

    /**
     * 获取全部流程分类
     * @return
     */
    @Override
    public List<HashMap<String, Object>> getFlowSortAll(){
        List<FlowSort> flowSortList= flowSortMapper.getFlowSortAll();
        List<HashMap<String, Object>> listMap= new ArrayList<HashMap<String, Object>>();
        for (FlowSort fs : flowSortList) {
            HashMap<String, Object> hashMap = new HashMap<>();
            //流程定义id
            hashMap.put("Id", fs.getId());
            //流程定义名称
            hashMap.put("name", fs.getName());
            hashMap.put("parentid", fs.getParentId());
            listMap.add(hashMap);
        }

        return listMap;
    }

    /**
     * 获取全部流程分类树
     * @return
     */
    @Override
    public List<FlowSort> getFlowSortTree(){
        List<FlowSort> flowSortList= flowSortMapper.getFlowSortAll();
        //2、组装树形结构
        List<FlowSort> newList = flowSortList.stream()
                .filter(t -> t.getParentId() == 0)
                .map((menu) -> {
                    menu.setChildren(this.getChildren(menu,flowSortList));
                    return menu;
                })
                .collect(Collectors.toList());

        return newList;
    }
    @Override
    public HashMap getSatrtPageData(){
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        String username = authentication.getName();
        HashMap map=new HashMap<>();
        List<HashMap<String,Object>> mapList=new ArrayList<>();
        List<FlowSort> flowSortList= flowSortMapper.getFlowSortAll();
        List<FlowEntity> commProceList=flowEntityMapper.getCommProceList(username);
        for(FlowSort fs:flowSortList){
            HashMap<String,Object> hashMap=new HashMap<>();
            hashMap.put("id",fs.getId());
            hashMap.put("name",fs.getName());

            List<FlowEntity> flowEntities=flowEntityMapper.getFlowListBySort(fs.getId().toString());

            if(flowEntities.size()>0){
                hashMap.put("flowList",flowEntities);
            }
            else{
                hashMap.put("flowList",new ArrayList<>());
            }
            mapList.add(hashMap);
        }
        map.put("commProceList",commProceList);
        map.put("flowList",mapList);

        return map;
    }
    /**
     * 递归查找当前菜单的子菜单
     * @param root 单个对象
     * @param all 所有的集合
     * @return 排序后的子类
     */
    private List<FlowSort> getChildren(FlowSort root,List<FlowSort> all){
        List<FlowSort> childrenList = all.stream()
                .filter(t -> t.getParentId() == root.getId())
                .map(g -> {
                    //找子菜单
                    g.setChildren(getChildren(g,all));
                    return g;
                })
                //菜单排序
                .collect(Collectors.toList());

        return childrenList;
    }

    /**
     * 新增流程类别
     * @param name
     * @param parentId
     * @return
     */
    @Override
    public String addFlowSort(String name, Long parentId){
        FlowSort flowSort=new FlowSort();
        flowSort.setName(name);
        flowSort.setParentId(parentId);
        int i=flowSortMapper.addFlowSort(flowSort);

        return "执行成功";
    }

    /**
     * 流程类别保存修改
     * @param id
     * @param name
     * @param parentId
     * @return
     */
    @Override
    public String saveFlowSort(Long id, String name, Long parentId){
        FlowSort flowSort=new FlowSort();
        flowSort.setId(id);
        flowSort.setName(name);
        flowSort.setParentId(parentId);
        int i=flowSortMapper.saveFlowSort(flowSort);

        return "执行成功";
    }

    /**
     * 删除流程定义
     * @param deploymentId
     * @return
     */
    @Override
    public String deleteDefinition(String deploymentId){
        repositoryService.deleteDeployment(deploymentId, true);
        return "执行成功";
    }
    /**
     * 删除流程分类
     * @param id
     * @param name
     * @param parentId
     * @return
     */
    @Override
    public String deleteFlowSort(Long id, String name, Long parentId){
        FlowSort flowSort=new FlowSort();
        flowSort.setId(id);
        flowSort.setName(name);
        flowSort.setParentId(parentId);
        int i=flowSortMapper.deleteFlowSort(flowSort);

        return "执行成功";
    }
}
